﻿// Imports
using System;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace Nickel
{

    /// <summary>
    /// Article
    /// </summary>
    public class Article
    {

        /// <summary>
        /// Author's GUID
        /// </summary>
        public string Author;

        /// <summary>
        /// List of comments
        /// </summary>
        public List<Comment> Comments;

        /// <summary>
        /// True if comments are allowed
        /// </summary>
        public bool CommentsEnabled;

        /// <summary>
        /// Creation date time
        /// </summary>
        public string CreationDateTime;

        /// <summary>
        /// Meta data description
        /// </summary>
        public string Description;

        /// <summary>
        /// Article ID
        /// </summary>
        public string ID;

        /// <summary>
        /// Meta data keyword list
        /// </summary>
        public Words Keywords;

        /// <summary>
        /// Last modified date time
        /// </summary>
        public string ModifiedDateTime;

        /// <summary>
        /// True if live
        /// </summary>
        public bool Published;

        /// <summary>
        /// List of IDs of authors subscribed to 
        /// this article's comments and updates
        /// </summary>
        public Words Subscriptions;

        /// <summary>
        /// Sub title / tag line
        /// </summary>
        public string SubTitle;

        /// <summary>
        /// List of category tags
        /// </summary>
        public Words Tags;

        /// <summary>
        /// Article content
        /// </summary>
        public string Text;

        /// <summary>
        /// Title of article
        /// </summary>
        public string Title;

        /// <summary>
        /// Creates a new article
        /// </summary>
        public Article()
        {
        }

        /// <summary>
        /// Build form string
        /// </summary>
        /// <param name="tags">Master tag list</param>
        /// <returns>Form as string</returns>
        public string Form(Words tags, string url)
        {

            // Choose title based on whether this is new or not
            string strFormTitle = ID == null ? Titles.ARTICLE_NEW : Titles.ARTICLE_UPDATE;
            string strDescription = Description == null ? string.Empty : Description;
            string strId = ID == null ? string.Empty : ID;
            string strKeywords = Keywords == null ? string.Empty : Keywords.Join(", ");
            string strSubTitle = SubTitle == null ? string.Empty : SubTitle;
            string strText = Text == null ? string.Empty : Text;
            string strTitle = Title == null ? string.Empty : Title;

            // Start form
            string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                "<h1>" + strFormTitle + "</h1>" +
                "<p>" + Instructions.ARTICLE + "</p>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_PUBLISH + "</div>" +
                "<div class=\"formInput\"><input type=\"checkbox\" name=\"" + Constants.INPUT_PUBLISH + "\" id=\"" + Constants.INPUT_PUBLISH + "\" value=\"true\" " + (Published ? "checked" : string.Empty) + " class=\"checkbox\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_COMMENTS_ENABLED + "</div>" +
                "<div class=\"formInput\"><input type=\"checkbox\" name=\"" + Constants.INPUT_COMMENTS_ENABLED + "\" id=\"" + Constants.INPUT_COMMENTS_ENABLED + "\" value=\"true\" " + (CommentsEnabled ? "checked" : string.Empty) + " class=\"checkbox\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_TITLE + "</div>" +
                "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_TITLE + "\" id=\"" + Constants.INPUT_TITLE + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ARTICLE + "');\" maxlength=\"256\" value=\"" + strTitle + "\" class=\"articleInput\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_SUBTITLE + "</div>" +
                "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_SUBTITLE + "\" id=\"" + Constants.INPUT_SUBTITLE + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ARTICLE + "');\" maxlength=\"256\" value=\"" + strSubTitle + "\" class=\"articleInput\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_DESCRIPTION + "</div>" +
                "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_DESCRIPTION + "\" id=\"" + Constants.INPUT_DESCRIPTION + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ARTICLE + "');\" maxlength=\"512\" value=\"" + strDescription + "\" class=\"articleInput\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_KEYWORDS + "</div>" +
                "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_KEYWORDS + "\" id=\"" + Constants.INPUT_KEYWORDS + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ARTICLE + "');\" maxlength=\"256\" value=\"" + strKeywords + "\" class=\"articleInput\" /></div>" +
                "</div>";

            // Check tag count
            if (tags.Count > 0)
            {

                // Add tags
                strForm += "<div class=\"formLine\">" +
                    "<div class=\"formLabel\">" + Labels.INPUT_TAGS + "</div>" +
                    "<div class=\"formCheckBoxes\">";

                // Iterate through tags
                foreach (string tag in tags)
                {

                    // See if this tag is selected
                    string strChecked = string.Empty;
                    if (Tags != null) 
                        foreach (string articleTag in Tags) 
                            if (articleTag.ToLower() == tag.ToLower()) 
                                strChecked = " checked";

                    // Add checkbox
                    strForm += "<div class=\"tagCheckbox\"><input type=\"checkbox\" name=\"" + Constants.INPUT_TAG_SELECT + "\" id=\"" + Constants.INPUT_TAG_SELECT + "\" value=\"" + tag + "\"" + strChecked + " />&nbsp;" + StringHelper.ToTitleCase(tag) + "</div>";

                }

                // Close line
                strForm += "</div>";

            }

            // Continue...
            strForm += "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_TAGS_NEW + "</div>" +
                "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_TAG_LIST + "\" id=\"" + Constants.INPUT_TAG_LIST + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ARTICLE + "');\" maxlength=\"256\" class=\"articleInput\" /></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">" + Labels.INPUT_TEXT + "</div>" +
                "<div class=\"formInput\">" + Constants.MARKUP_BAR + 
                Constants.UPLOAD_BAR.Replace("###url###", url) + "</div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">&nbsp;</div>" +
                "<div class=\"formInput\"><textarea name=\"" + Constants.INPUT_TEXT + "\" id=\"" + Constants.INPUT_TEXT + "\" class=\"articleText\">" + strText + "</textarea></div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">&nbsp;</div>" +
                "<div class=\"formInput\">&nbsp;</div>" +
                "</div>" +
                "<div class=\"formLine\">" +
                "<div class=\"formLabel\">&nbsp;</div>" +
                "<div class=\"formInput\">";

            // Add ID
            if (ID != null) 
                strForm += "<input type=\"hidden\" id=\"" + Constants.INPUT_ID + "\" name=\"" + Constants.INPUT_ID + "\" value=\"" + strId + "\">";

            // Finish form
            strForm += "<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_ARTICLE + "');\" value=\"" + Labels.SUBMIT_ARTICLE + "\" />" +
                "<div id=\"" + Constants.TARGET_FORM_ERROR + "\" class=\"articleError\"></div>" +
                "</div>" + 
                "</div>";

            // Return form
            return strForm;

        }

        /// <summary>
        /// Find comments with this author ID
        /// </summary>
        /// <param name="authorId">Poster's e-mail address</param>
        /// <returns>List of comments</returns>
        public List<Comment> GetCommentByAuthorId(string authorId)
        {

            // Initialize return list
            List<Comment> comments = new List<Comment>();

            // Find comment
            int commentCount = Comments.Count;
            for (int i = 0; i < commentCount; i++) 
                if (Comments[i].Author == authorId) 
                    comments.Add(Comments[i]);

            // Null if none found
            if (comments.Count < 1) 
                comments = null;

            // Return list
            return comments;

        }

        /// <summary>
        /// Find comment with this ID
        /// </summary>
        /// <param name="id">Comment ID</param>
        /// <returns>The comment</returns>
        public Comment GetCommentById(string id)
        {

            // Find comment
            int commentCount = Comments.Count;
            for (int i = 0; i < commentCount; i++) 
                if (Comments[i].ID == id) 
                    return Comments[i];

            // Return null if not found
            return null;

        }

        /// <summary>
        /// Check if article has this keyword
        /// </summary>
        /// <param name="keyword">The keyword</param>
        /// <returns>True if article has this keyword</returns>
        public bool HasKeyword(string keyword)
        {

            // Find keyword
            keyword = StringHelper.Encode(keyword);
            int keywordCount = Keywords.Count;
            for (int i = 0; i < keywordCount; i++) 
                if (StringHelper.Encode(Keywords[i]) == keyword) 
                    return true;

            // Return false if not found
            return false;

        }

        /// <summary>
        /// Check if article has this tag
        /// </summary>
        /// <param name="tag">The tag</param>
        /// <returns>True if article has this tag</returns>
        public bool HasTag(string tag)
        {

            // Find tag
            tag = StringHelper.Encode(tag);
            int tagCount = Tags.Count;
            for (int i = 0; i < tagCount; i++)
                if (StringHelper.Encode(Tags[i]) == tag) 
                    return true;

            // Return false if not found
            return false;

        }

        /// <summary>
        /// Update article using form data
        /// </summary>
        /// <param name="Form">Pass in Request.Form</param>
        public string Update(NameValueCollection Form)
        {

            // Declare return string
            string strMessage = string.Empty;

            // Check required fields
            if (Form[Constants.INPUT_TITLE].Length <= 0) 
                strMessage = Errors.ARTICLE_TITLE_MISSING;
            if (strMessage == string.Empty && Form[Constants.INPUT_SUBTITLE].Length <= 0) 
                strMessage = Errors.ARTICLE_SUBTITLE_MISSING;
            if (strMessage == string.Empty && Form[Constants.INPUT_DESCRIPTION].Length <= 0) 
                strMessage = Errors.ARTICLE_DESCRIPTION_MISSING;
            if (strMessage == string.Empty && Form[Constants.INPUT_KEYWORDS].Length <= 0) 
                strMessage = Errors.ARTICLE_KEYWORDS_MISSING;
            if (strMessage == string.Empty && Form[Constants.INPUT_TEXT].Length <= 0) 
                strMessage = Errors.ARTICLE_TEXT_MISSING;
            if (strMessage == string.Empty)
            {

                // This is a new article
                if (ID == null)
                {

                    // Get new ID
                    ID = StringHelper.NewGuid;

                    // Initialize lists
                    Comments = new List<Comment>();
                    Keywords = new Words();
                    Subscriptions = new Words();
                    Tags = new Words();

                    // Set creation date
                    CreationDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);

                }

                // Set modfied date time
                ModifiedDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);

                // Clear tags
                Tags.Clear();

                // Combine tag lists
                string strTags = Form[Constants.INPUT_TAG_SELECT] + "," + Form[Constants.INPUT_TAG_LIST];
                foreach (string tag in strTags.Split(",".ToCharArray()))
                {

                    // Clean up tag
                    string strTag = tag.ToLower().Trim();

                    // Add tag to list
                    if (strTag.Length > 0) 
                        Tags.Add(strTag);

                }

                // Sort tags
                Tags.Sort();

                // Iterate through keys
                foreach (string key in Form)
                {

                    // Key on key
                    switch (key)
                    {

                        case Constants.INPUT_COMMENTS_ENABLED:

                            // Set comments flag
                            CommentsEnabled = Form[Constants.INPUT_COMMENTS_ENABLED].ToLower() == "true";

                            break;
                        case Constants.INPUT_DESCRIPTION:

                            // Set description
                            Description = Form[Constants.INPUT_DESCRIPTION];

                            break;
                        case Constants.INPUT_KEYWORDS:

                            // Clear current keywords
                            Keywords.Clear();

                            // Iterate through keywords
                            foreach (string keyword in Form[Constants.INPUT_KEYWORDS].Split(",".ToCharArray()))
                            {

                                // Clean up keyword
                                string strKeyword = keyword.ToLower().Trim();

                                // Check length
                                if (strKeyword.Length > 0)
                                {

                                    // Check if keyword already exists (prevents duplicates)
                                    bool bKeywordExists = false;
                                    foreach (string addedKeyword in Keywords) 
                                        if (addedKeyword.ToLower() == strKeyword) 
                                            bKeywordExists = true;

                                    // Add keyword if not found
                                    if (!bKeywordExists) 
                                        Keywords.Add(strKeyword);

                                }

                            }

                            // Sort keywords
                            Keywords.Sort();

                            break;
                        case Constants.INPUT_PUBLISH:

                            // Set publish flag
                            Published = Form[Constants.INPUT_PUBLISH].ToLower() == "true";

                            break;
                        case Constants.INPUT_SUBTITLE:

                            // Set subtitle
                            SubTitle = Form[Constants.INPUT_SUBTITLE];

                            break;
                        case Constants.INPUT_TEXT:

                            // Set content
                            Text = Form[Constants.INPUT_TEXT].Replace("<", "&lt;").Replace(">", "&gt;");

                            break;
                        case Constants.INPUT_TITLE:

                            // Set title
                            Title = Form[Constants.INPUT_TITLE];

                            break;

                    }

                }

            }

            // Return message
            return strMessage;

        }

    }

}
